package com.vains.utils;

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * spring boot应用帮助类
 *
 * @author vains
 * @version 1.0
 * @since 2020/6/27 18:02
 **/
public class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    private SpringContextUtils() {}

    /**
     * 获取当前response对象
     * @return HttpServletResponse
     */
    public static HttpServletResponse getCurrentResponse() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Assert.notNull(requestAttributes, "servlet请求和HTTP会话作用域访问对象获取失败");
        return requestAttributes.getResponse();
    }

    /**
     * 获取当前request对象
     * @return HttpServletRequest
     */
    public static HttpServletRequest getCurrentRequest() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        Assert.notNull(requestAttributes, "servlet请求和HTTP会话作用域访问对象获取失败");
        return requestAttributes.getRequest();
    }

    /**
     * 获取当前Session对象
     * @return HttpSession
     */
    public static HttpSession getCurrentSession() {
        return getCurrentRequest().getSession();
    }

    /**
     * 获取当前request携带的所有cookie
     * @return HttpSession
     */
    public static Cookie[] getCookies() {
        return getCurrentRequest().getCookies();
    }

    /**
     * 根据cookie的key获取对应的value
     * @param cookieName cookie的key
     * @return cookie值
     */
    public static String getCookie(String cookieName) {
        Assert.hasLength(cookieName, "cookieName不能为空!");
        Cookie[] cookies = getCookies();
        Assert.notEmpty(cookies, "当前请求没有cookie!");
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(cookieName)) {
                return cookie.getValue();
            }
        }
        return null;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        if (SpringContextUtils.applicationContext == null) {
            SpringContextUtils.applicationContext = applicationContext;
        }
    }

    /**
     * 获取静态变量中的application Context
     * @return ApplicationContext
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 检测application context是否已经注入
     */
    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new RuntimeException("当前applicationContext尚未注入，请注入后获取.");
        }
    }

    /**
     * 根据bean的名称获取Bean 自动转型为所赋值对象的类型
     * @param name ioc中bean的名字
     * @param <T> 类型
     * @return 返回一个对象
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) {
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }

    /**
     * 根据bean的名称获取Bean 自动转型为所赋值对象的类型
     * @param clazz bean的class
     * @param <T> 类型
     * @return 返回一个对象
     */
    public static <T> T getBean(Class<T> clazz) {
        checkApplicationContext();
        return applicationContext.getBean(clazz);
    }

    /**
     * 获取请求中的token
     * @return token
     */
    public static String getToken() {
        String tokenType = "Bearer";
        HttpServletRequest currentRequest = getCurrentRequest();
        String token = currentRequest.getParameter("access_token");
        if (StringUtils.isEmpty(token)) {
            token = currentRequest.getHeader("Authorization");
            if (!StringUtils.isEmpty(token) && token.startsWith(tokenType)) {
                return token.substring(tokenType.length()).trim();
            }
        }
        return token;
    }

}
